#include <complex>
#include <iostream>
#include <string>
#include <tuple>
#include <utility>


using namespace std;

namespace YTQ {

template <typename... Types> class Tuple;

template <> class Tuple<> {};

template <typename Head, typename... Types>
class Tuple<Head, Types...> : private Tuple<Types...> {
  public:
    typedef Tuple<Types...> Inherited;
    Tuple() {}
    Tuple(Head h, Types... args) : m_head(h), Inherited(args...) {
        cout<<"head:"<<m_head<<"\t"<<sizeof...(args)<<endl;
    }
    Head head() { return m_head; }
    Inherited& tail() { return *this; }

  public:
    Head m_head;
};

ostream& operator<<(ostream &os, Tuple<> &tpe)
{
    os<<"\tcall end\t"<<endl;
    return os;
}

template<typename Head,typename... Tail>
ostream& operator<<(ostream &os, Tuple<Head,Tail...> &tpe)
{
    os<<tpe.head()<<",";
    operator<<(os, tpe.tail());
    return os;
}


} // namespace YTQ

void testTuple() {
    YTQ::Tuple<int,string,float> mt(10,"abc",4.3);
    cout<<mt.head()<<endl;
    cout<<(mt.tail()).head()<<endl;
    cout<<((mt.tail()).tail()).head()<<endl;

    cout<<"-------------------------------"<<endl;
    cout<<"tuple out<"<<mt<<">"<<endl;
}
#if 0
void testTuple1() {
    cout << "1 test sizeof output:" << endl;
    cout << "string sizeof =" << sizeof(std::string) << endl;
    cout << "double sizeof =" << sizeof(double) << endl;
    cout << "float sizeof =" << sizeof(float) << endl;
    cout << "int sizeof =" << sizeof(int) << endl;
    cout << "complex<double> sizeof= " << sizeof(std::complex<double>) << endl;
    cout << "///////////////////////////////////////////////////////////"
         << endl;

    cout << "2 test tuple size:" << endl;
    std::tuple<string, int, int, complex<double>> t;
    cout << "tuple size = " << sizeof(t) << endl;
    cout << "///////////////////////////////////////////////////////////"
         << endl;

    tuple<int, float, string> t1(41, 3.3, "ytq");
    cout << "3 tuple<int,float,string> size =" << sizeof(t1) << endl;
    cout << "t1 value:" << get<0>(t1) << "\t" << get<1>(t1) << "\t"
         << get<2>(t1) << endl;

    auto t2 = make_tuple(22, 44, "stacy");
    cout << "t2 size=" << sizeof(t2) << endl;
    cout << "t2 value:" << get<0>(t2) << "\t" << get<1>(t2) << "\t"
         << get<2>(t2) << endl;

    get<1>(t2) = get<1>(t1);
    cout << "t2 size=" << sizeof(t2) << endl;
    cout << "t2 value:" << get<0>(t2) << "\t" << get<1>(t2) << "\t"
         << get<2>(t2) << endl;
    cout << "/////////////////////////////////////////////////////" << endl;

    auto t3 = make_tuple(77, 1.1, "test");
    int t3Int;
    float t3Float;
    string t3Str;
    tie(t3Int, t3Float, t3Str) = t3;
    cout << "t3 tie:" << t3Int << "\t" << t3Float << "\t" << t3Str << endl;
    cout << "t3 tuple:" << get<0>(t3) << "\t" << get<1>(t3) << "\t"
         << get<2>(t3) << endl;
    typedef tuple<int, float, string> TupleType;
    cout << "tuple size:" << tuple_size<decltype(t3)>::value << endl;
    cout << "tuple t3 size:" << std::tuple_size<decltype(t3)>::value << endl;
    typedef tuple_element<1, TupleType>::type T;
    T fl = 1.0;
    cout << "f1:" << fl << endl;

    auto t4 = std::pair<int, float>{2, 3.4};

    std::tuple_element<0, decltype(t4)>::type t4Int = t4.first;
    std::tuple_element<1, decltype(t4)>::type t4Float = t4.second;
    cout << "t4 value:" << t4Int << "\t" << t4Float << endl;
}
#endif